package com.jilujia.domain.hotel.service;

import java.util.List;

import net.sf.ehcache.Ehcache;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.jilujia.domain.JilujiaSpecifications;
import com.jilujia.domain.hotel.Hotel;
import com.jilujia.domain.hotel.HotelManager;
import com.jilujia.domain.hotel.HotelViewCountManager;
import com.jilujia.domain.hotel.repository.HotelRepository;
import com.jilujia.domain.region.Region;
import com.jilujia.domain.user.UserFollowHotelManager;
import com.jilujia.framework.domain.AbstractService;
import com.jilujia.framework.domain.SearchCriteria;
import com.jilujia.web.CacheConstants;

@Service("hotelService")
@Transactional(readOnly = true)
public class HotelServiceImpl extends AbstractService implements HotelService {

	private static final Logger LOG = LoggerFactory.getLogger(HotelServiceImpl.class);

	@Autowired
	private HotelRepository hotelRepository;

	@Autowired
	private CacheManager cacheManager;

	public Hotel findHotelById(Long id) {
		Hotel hotel = hotelRepository.findOne(id);
		return hotel;
	}

	public Integer getViewCount(Long hotelId) {
		HotelViewCountManager hotelViewCountManager = getApplicationContext().getBean(HotelViewCountManager.class);

		Integer viewCount = hotelViewCountManager.getViewCount(hotelId);

		hotelViewCountManager.addViewCount(hotelId);
		return viewCount;
	}

	public Page<Hotel> findHotelsByCriteria(final HotelSearchCriteria criteria) {
		LOG.debug("findHotels invoked");
		PageRequest pageRequest = new PageRequest(criteria.getPage(), criteria.getPageSize());

		Specification<Hotel> specification = JilujiaSpecifications.generateHotelSpecification(criteria);

		Page<Hotel> hotels = hotelRepository.findAll(specification, pageRequest);

		return hotels;
	}

	public Hotel createHotel() {
		LOG.debug("create new hotel entry");
		return new Hotel();
	}

	@Transactional
	public Hotel saveHotel(Hotel hotel) {
		HotelManager hotelManager = getApplicationContext().getBean(HotelManager.class);
		hotelManager.saveHotel(hotel);
		hotel = hotelManager.getInstance();
		return hotel;
	}

	public List<Hotel> findUserFollowedHotelsByUserId(Long userId) {
		List<Hotel> hotels = hotelRepository.findHotelsByUserId(userId);
		return hotels;
	}

	@Scheduled(cron = "0 0/20 * * * ?")
	@Transactional
	public void refleshHotelViewCount() {
		LOG.debug("refleshHotelViewCount begin");
		Ehcache ehcache = (Ehcache) cacheManager.getCache(CacheConstants.HOTELS_VIEWCOUNT_CACHENAME).getNativeCache();
		for (Object key : ehcache.getKeys()) {
			String strKey = (String) key;
			Integer viewCount = (Integer) ehcache.get(strKey).getObjectValue();
			String hotelId = strKey.substring(strKey.indexOf(":") + 1);
			LOG.debug("refleshHotelViewCount:" + hotelId + ":" + viewCount);
			HotelViewCountManager hotelViewCountManager = getApplicationContext().getBean(HotelViewCountManager.class);
			hotelViewCountManager.save(Long.valueOf(hotelId), viewCount);
			// use strkey and followcount batch update count in hotel
		}
		LOG.debug("refleshHotelViewCount end");
	}

	public List<Hotel> findTop10Hotels() {
		return hotelRepository.findTop10Hotels();
	}

	@Transactional
	public void followHotel(Long userId, Long hotelId) {
		// 建立关联
		UserFollowHotelManager userFollowManager = getApplicationContext().getBean(UserFollowHotelManager.class);
		userFollowManager.follow(userId, hotelId);
		// Hotel的粉丝加一
		// TODO follow count 需要换做法
		HotelManager hotelManager = getApplicationContext().getBean(HotelManager.class);
		hotelManager.addFollowCount(hotelId);
		// User的关注加一
		// 发消息告诉Hotel，一个新的user关注了你（event listener模式）

	}

	@Transactional
	public void unfollowHotel(Long userId, Long hotelId) {
		UserFollowHotelManager userFollowManager = getApplicationContext().getBean(UserFollowHotelManager.class);
		userFollowManager.unfollow(userId, hotelId);
		// Hotel的粉丝减一
		// TODO follow count 需要换做法
		HotelManager hotelManager = getApplicationContext().getBean(HotelManager.class);
		hotelManager.subFollowCount(hotelId);
		// User的关注减一
		// 发消息告诉Hotel，一个user取消关注了你（event listener模式）
	}

	@Override
	public List<Hotel> findTop10HotelsByRegion(Region region) {
		List<Hotel> hotels = hotelRepository.findHotelsByRegion(region.getId(), SearchCriteria.getTop10PageRequest());
		return hotels;
	}

}
